/**
 * @author		Sergey Suzdalskiy
 * @e-mail:		sergey.suzdalskiy@gmail.com
 */
package ua.kiev.gcore.logger {
	import flash.display.Sprite;
	import flash.system.System;
	import flash.utils.getTimer;
	
	import ua.kiev.gcore.logger.target.ILogTarget;
	
	public class Logger {
		
		public static const messagesShowLimit:int = 100;
		
		public static var INFO_LEVEL:int = 3;
		public static var DEBUG_LEVEL:int = 2;
		public static var ERROR_LEVEL:int = 1;
		public static var All_LEVEL:int = 0;
		
		public static var container:Sprite;
		private static var logTarget:ILogTarget;
		private static var enableDebugMode:Boolean;
		
		private static var traceLevel:int = ERROR_LEVEL;
				
		/**
		 * logger setTarget
		 * @param lPanel visual component for view log
		 */
		public static function setTarget(lTarget:ILogTarget):void {
			if(lTarget){
				logTarget = lTarget;
				enableDebugMode = true
			}
		}
		
		public static function copyToClipboard(level:int):void{
			var result:String = new String();
			var messages:Vector.<LoggerMessage> = LoggerMessageCollection.GetByLevel(level);
			for each(var message:LoggerMessage in messages){
				result += message.getFormatedMessage() + "\n";
			}
			
			System.setClipboard(result);
		}
		public static function setLevel(level:int):void{
			traceLevel = level;
			if(logTarget != null){
				logTarget.clear();
			}
			
			var messages:Vector.<LoggerMessage> = LoggerMessageCollection.GetLastByLevel(traceLevel, messagesShowLimit);
			for each(var message:LoggerMessage in messages){
				append(message);
			}
		}

		public static function traceFormatString(str:String):String{
			return "[" + getTime() + "] " + str;
		}
		/*
		Array		object
		Boolean		boolean
		Function	function
		int			number
		Number		number
		Object		object
		String		string
		uint		number
		XML			xml
		XMLList		xml
		*/
		public static function DEBUG_OBJ(data:Object, name:String = ""):void{	
			var deepLevel:int = 0;
			const deepLevelMax:int = 10;				
			var tab:String = "";
			var traceComplete:Boolean = false;
			
			var datas:Array = [data];
			var newLevel:Array = new Array();
			
			DEBUG(name);
			
			while(!traceComplete){
				
				if((deepLevel < deepLevelMax) && (datas.length)){
					
					for each(var tmpData:Object in datas){
						for(var key:String in tmpData){
							if(tmpData[key] == null){
								DEBUG(" - " + tab + key + ": " + "null");
								continue;
							}
							if((typeof(tmpData[key]) == "number")||(typeof(tmpData[key]) == "string")||(typeof(tmpData[key]) == "boolean")){
								DEBUG(" - " + tab + key + ": " + tmpData[key].toString());
							}else{
								DEBUG(" - " + tab + key + ": " + tmpData[key].toString());
//								append(key + ": " + tmpData[key].toString(), " - " + tab, 0x000000, DEBUG_LEVEL);
								if(tmpData[key] is Array){
									DEBUG(" - " + tab + "length: " + (tmpData[key] as Array).length.toString());
//									append("length: " + (tmpData[key] as Array).length.toString(), " -  " + tab, 0x000000, DEBUG_LEVEL);
								}
								newLevel.push(data[key]);									
							}
						}
					}
					
					datas = new Array();
					if(newLevel.length){
						datas = newLevel;
						newLevel = new Array();
						++deepLevel;
						tab += " ";
					}else{
						traceComplete = true;
					}
					
				}else{
					DEBUG("deep level is max");
//					append("deepLevelMax!", "", 0x000000, DEBUG_LEVEL);
					traceComplete = true;
				}
			}
				
		}
		
		public static function INFO(...params):void {
			var message:LoggerMessage =  LoggerMessageCollection.AddNewMessage(toString(params), LoggerMessage.INFO_TYPE, INFO_LEVEL);
			trace(message.getFormatedMessage());
			if((enableDebugMode) && (traceLevel == INFO_LEVEL)){
				append(message);
			}
				//			var message:LoggerMessage = 
				//			append(message.Message, "INFO", 0x0066FF, SYSTEM_LEVEL); 
		}
			
		
		public static function DEBUG(...params):void {
			var message:LoggerMessage =  LoggerMessageCollection.AddNewMessage(toString(params), LoggerMessage.DEBUG_TYPE, DEBUG_LEVEL);
			trace(message.getFormatedMessage());
			if((enableDebugMode) && (traceLevel == DEBUG_LEVEL)){
				append(message);
			}
//			append(toString(params), "DEBUG", 0x006600, ADMIN_LEVEL); 
		}
		
		public static function WARNING(...params):void {
			var message:LoggerMessage =  LoggerMessageCollection.AddNewMessage(toString(params), LoggerMessage.WARNING_TYPE, ERROR_LEVEL);
			trace(message.getFormatedMessage());
			if((enableDebugMode) && (traceLevel == ERROR_LEVEL)){
				append(message);
			}
//			append(toString(params), "WARNING", 0xFF9900, ADMIN_LEVEL); 
		}
		
		public static function ERROR(...params):void {
			var message:LoggerMessage =  LoggerMessageCollection.AddNewMessage(toString(params), LoggerMessage.ERROR_TYPE, ERROR_LEVEL);
			trace(message.getFormatedMessage());
			if((enableDebugMode) && (traceLevel == ERROR_LEVEL)){
				append(message);
			}
//			append(toString(params), "ERROR", 0xFF0000, USER_LEVEL); 
		}
		
		private static function append(message:LoggerMessage):void {			
			if (logTarget != null) {
				logTarget.append(message);
			}
		}
		
		private static function toString(params:Array):String{
			var result:String = "";
			for each(var i:* in params){
				if(i != null){
					result += i.toString();
				}else{
					result += i;
				}
			}
			
			return result;
		}
		
		/**
		 * turn on or off status
		 */
		public static function set enabled(value:Boolean):void {
			enableDebugMode = value;
			if(enableDebugMode == false){
				if(logTarget){
					logTarget.clear();				
				}
			}else{
				setLevel(traceLevel);
			}
						
		}
		public static function get enabled():Boolean {
			return enableDebugMode;
		}
		
		/**
		 * get time since launch
		 */
		private static function getTime():String {
			return (getTimer() / 1000).toFixed(3);
		}
	}
}